TrialCleanerGUI.m 45 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516
  1. function varargout = TrialCleanerGUI(varargin)
  2. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  3. % Performs ICA decomposition and component removal. %
  4. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  5. % Copyright (C) 2013-2014, Michael J. Cheung
  6. %
  7. % This file is a part of the MEG & PLS Pipeline (MEGPLS). For more
  8. % details, see the documentation included with the software package.
  9. %
  10. % MEGPLS is free software: you can redistribute it and/or modify it under
  11. % the terms of the GNU General Public License version 2 as published by
  12. % the Free Software Foundation. This program is distributed in the hope
  13. % that it will be useful, but WITHOUT ANY WARRANTY; without even the
  14. % implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  15. % See the GNU General Public License for more details.
  16. %
  17. % You should have received a copy of the GNU General Public License along
  18. % with this program. If not, you can download the license here:
  19. % <http://www.gnu.org/licenses/old-licenses/gpl-2.0>.
  20. % Last Modified by GUIDE v2.5 04-Sep-2014 18:30:53
  21. % Begin initialization code - DO NOT EDIT
  22. gui_Singleton = 1;
  23. gui_State = struct('gui_Name', mfilename, ...
  24. 'gui_Singleton', gui_Singleton, ...
  25. 'gui_OpeningFcn', @TrialCleanerGUI_OpeningFcn, ...
  26. 'gui_OutputFcn', @TrialCleanerGUI_OutputFcn, ...
  27. 'gui_LayoutFcn', [] , ...
  28. 'gui_Callback', []);
  29. if nargin && ischar(varargin{1})
  30. gui_State.gui_Callback = str2func(varargin{1});
  31. end
  32. if nargout
  33. [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
  34. else
  35. gui_mainfcn(gui_State, varargin{:});
  36. end
  37. % End initialization code - DO NOT EDIT
  38. %--- Executes just before TrialCleanerGUI is made visible. ---%
  39. %-----------------------------------------------------%
  40. function TrialCleanerGUI_OpeningFcn(hObject, eventdata, handles, varargin)
  41. % This function has no output args, see OutputFcn.
  42. % hObject handle to figure
  43. % eventdata reserved - to be defined in a future version of MATLAB
  44. % handles structure with handles and user data (see GUIDATA)
  45. % varargin command line arguments to TrialCleanerGUI (see VARARGIN)
  46. % Choose default command line output for TrialCleanerGUI
  47. handles.output = hObject;
  48. % Make sure toolbox paths are added:
  49. [PipelineDir, ~, ~] = fileparts(which('TrialCleanerGUI.m'));
  50. handles.PipelineDir = PipelineDir;
  51. addpath(genpath(PipelineDir));
  52. rmpath([PipelineDir,'/DEFAULT_SETTINGS']); % Make sure its calling from DataID
  53. rmpath([PipelineDir,'/TEMPORARY_FIXES']); % Make sure its calling from FT toolbox
  54. CheckToolboxPaths(PipelineDir);
  55. if exist('ErrorLog_TrialCleaner.txt', 'file')
  56. system('rm ErrorLog_TrialCleaner.txt');
  57. end
  58. % Initializes variables being displayed:
  59. handles.paths.Rootpath = [];
  60. handles.paths.DataID = [];
  61. handles.name.DataID = [];
  62. handles.name.GroupID = [];
  63. handles.name.SubjID = [];
  64. handles.name.CondID = [];
  65. handles.paths.InputPreprocMEG = [];
  66. handles.paths.BackupOrigFile = [];
  67. handles.gui.InpOutStatus = [];
  68. handles.FTcfg = [];
  69. % Save handles:
  70. guidata(hObject, handles);
  71. % UIWAIT makes TrialCleanerGUI wait for user response (see UIRESUME)
  72. % uiwait(handles.figure1);
  73. %--- Outputs from this function are returned to the command line. ---%
  74. %--------------------------------------------------------------------%
  75. function varargout = TrialCleanerGUI_OutputFcn(hObject, eventdata, handles)
  76. % varargout cell array for returning output args (see VARARGOUT);
  77. % hObject handle to figure
  78. % eventdata reserved - to be defined in a future version of MATLAB
  79. % handles structure with handles and user data (see GUIDATA)
  80. % Get default command line output from handles structure
  81. varargout{1} = handles.output;
  82. %===================================%
  83. % FUNCTIONS FOR SELECTING ROOTPATH: %
  84. %===================================%
  85. %--- Executes on button press in ButtonSetRootpath. ---%
  86. %------------------------------------------------------%
  87. function ButtonSetRootpath_Callback(hObject, eventdata, handles)
  88. if ~isempty(handles.name.DataID)
  89. prompt = {'WARNING:'; '';
  90. 'Changing root directory will clear all current settings!'; '';
  91. 'Do you wish to continue?'};
  92. ChangeDir = questdlg(prompt, 'WARNING:', 'YES', 'NO', 'NO');
  93. if strcmp(ChangeDir, 'NO')
  94. return;
  95. end
  96. end
  97. % Select and set Rootpath:
  98. SelectedPath = uigetdir;
  99. if SelectedPath == 0
  100. return % If user cancels
  101. end
  102. handles.paths.Rootpath = SelectedPath;
  103. set(handles.TextboxRootpath, 'String', handles.paths.Rootpath);
  104. % Start Waitbox:
  105. WaitBox = StartWaitBox('SETTING ROOT DIRECTORY:');
  106. % Reset DataID:
  107. handles.name.DataID = [];
  108. handles.paths.DataID = [];
  109. set(handles.TextboxDataID, 'String', 'Not Selected.');
  110. % Reset settings & GUI panels:
  111. handles = ResetGroupIDSettings (handles);
  112. handles = ResetSubjIDSettings (handles);
  113. handles = ResetCondIDSettings (handles);
  114. handles = ResetStatusSettings (handles);
  115. handles.paths.InputPreprocMEG = [];
  116. handles.paths.BackupOrigFile = [];
  117. % Update settings & GUI panels (to enable/disable):
  118. % Note: Don't redetect or compile paths yet since no DataID yet.
  119. handles = UpdateGroupIDSettings (handles);
  120. handles = UpdateSubjIDSettings (handles);
  121. handles = UpdateCondIDSettings (handles);
  122. handles = UpdateStatusSettings (handles);
  123. % Save handles:
  124. guidata(hObject, handles);
  125. close(WaitBox);
  126. %--- Textbox to display selected Rootpath: ---%
  127. %---------------------------------------------%
  128. function TextboxRootpath_Callback(hObject, eventdata, handles)
  129. EnteredText = get(handles.TextboxRootpath, 'String');
  130. if ~isequal(EnteredText, handles.paths.Rootpath)
  131. set(handles.TextboxRootpath, 'String', handles.paths.Rootpath);
  132. msgbox('Note: Use button to change Rootpath.')
  133. end
  134. %=========================================%
  135. % FUNCTIONS FOR READING & LOADING DATAID: %
  136. %=========================================%
  137. %--- Textbox to display current DataID: ---%
  138. %------------------------------------------%
  139. function TextboxDataID_Callback(hObject, eventdata, handles)
  140. EnteredText = get(handles.TextboxDataID, 'String');
  141. if ~isequal(EnteredText, handles.name.DataID)
  142. set(handles.TextboxDataID, 'String', handles.name.DataID);
  143. msgbox('Note: Use button to change DataID.')
  144. end
  145. %--- Executes on button press in ButtonLoadDataID. ---%
  146. %-----------------------------------------------------%
  147. function ButtonLoadDataID_Callback(hObject, eventdata, handles)
  148. if isempty(handles.paths.Rootpath)
  149. msgbox('Warning: Select target directory first.', 'Warning:');
  150. return;
  151. end
  152. % Get DataID folders in current rootpath:
  153. DetectedFolders = dir([handles.paths.Rootpath,'/DataID_*']);
  154. DetectedFolders = [DetectedFolders; dir([handles.paths.Rootpath,'/DataID-ICAclean_*'])];
  155. RemoveIndex = [];
  156. for d = 1:length(DetectedFolders)
  157. if DetectedFolders(d).isdir ~= 1
  158. RemoveIndex = [RemoveIndex, d]; % Get unwanted indices
  159. end
  160. end
  161. DetectedFolders(RemoveIndex) = [];
  162. if isempty(DetectedFolders)
  163. msgbox('Error: No DataID folders detected inside target directory.', 'Error:');
  164. return;
  165. end
  166. % List DataID folders for selection:
  167. DetectedFolders = {DetectedFolders.name};
  168. SelectedIndex = listdlg('PromptString', 'Select DataID to load:',...
  169. 'ListSize', [300, 300], 'SelectionMode', 'single', 'ListString', DetectedFolders);
  170. if isempty(SelectedIndex) % If user cancels.
  171. return;
  172. end
  173. SelectedDataID = DetectedFolders{SelectedIndex};
  174. if strcmp(SelectedDataID(1:7), 'DataID_')
  175. SelectedDataID(1:7) = []; % Remove "DataID_" prefix to get DataID tag.
  176. FullpathDataID = [handles.paths.Rootpath,'/DataID_',SelectedDataID];
  177. elseif strcmp(SelectedDataID(1:16), 'DataID-ICAclean_')
  178. SelectedDataID(1:16) = []; % Remove "DataID-ICAclean_" prefix to get DataID tag.
  179. FullpathDataID = [handles.paths.Rootpath,'/DataID-ICAclean_',SelectedDataID];
  180. end
  181. % Check or create settings .m file for ft_rejectvisual:
  182. if ~exist([FullpathDataID,'/SETTINGS'], 'dir')
  183. success = mkdir([FullpathDataID,'/SETTINGS']);
  184. if success == 0
  185. message = {'ERROR:'; '';
  186. 'Failed to create SETTINGS folder in selected DataID.';
  187. 'Ensure you have proper folder and file permissions.'};
  188. msgbox(message, 'ERROR:')
  189. return;
  190. end
  191. end
  192. DefaultSettingsFile = [handles.PipelineDir,'/DEFAULT_SETTINGS/Settings_RejectVisual.m'];
  193. NewSettingsFile = [FullpathDataID,'/SETTINGS/Settings_RejectVisual.m'];
  194. if ~exist(NewSettingsFile, 'file')
  195. status = copyfile(DefaultSettingsFile, NewSettingsFile, 'f');
  196. if status == 0
  197. message = {'ERROR:'; '';
  198. 'Failed to create "ft_rejectvisual" settings file for selected DataID.';
  199. 'Could not copy file from [MEG]PLS "DEFAULT_SETTINGS" directory.';
  200. 'Check for proper folder and file permissions.'};
  201. msgbox(message, 'ERROR:')
  202. return;
  203. end
  204. end
  205. % Set as current DataID:
  206. handles.name.DataID = SelectedDataID;
  207. handles.paths.DataID = FullpathDataID;
  208. % Reset settings & GUI panels:
  209. handles = ResetGroupIDSettings (handles);
  210. handles = ResetSubjIDSettings (handles);
  211. handles = ResetCondIDSettings (handles);
  212. handles = ResetStatusSettings (handles);
  213. handles.paths.InputPreprocMEG = [];
  214. handles.paths.BackupOrigFile = [];
  215. % Compile Group, Subj, and CondIDs for DataID:
  216. % Note: Also initializes Group, Subj, CondIDs.
  217. handles = DetectGroupSubjCond(handles);
  218. if isempty(handles.name.GroupID)
  219. msgbox('ERROR: No GroupID folders detected for selected DataID.')
  220. return;
  221. end
  222. % Compile paths & initialize other variables:
  223. for g = 1:length(handles.name.GroupID)
  224. for s = 1:length(handles.name.SubjID{g})
  225. for c = 1:length(handles.name.CondID)
  226. handles = CompilePaths(handles, g, s, c);
  227. try
  228. handles.gui.InpOutStatus{g}{s,c};
  229. catch
  230. handles.gui.InpOutStatus{g}{s,c} = [];
  231. end
  232. end
  233. end
  234. end
  235. % Update settings & GUI panels:
  236. handles = UpdateGroupIDSettings (handles);
  237. handles = UpdateSubjIDSettings (handles);
  238. handles = UpdateCondIDSettings (handles);
  239. % Detect & update status:
  240. for g = 1:length(handles.name.GroupID)
  241. StatusWaitbar = waitbar(0, ['Please wait. Scanning status for: ', ...
  242. handles.name.GroupID{g}], 'Windowstyle', 'modal');
  243. for s = 1:length(handles.name.SubjID{g})
  244. waitbar(s/length(handles.name.SubjID{g}), StatusWaitbar);
  245. for c = 1:length(handles.name.CondID)
  246. handles = DetectStatus(handles, g, s, c);
  247. end
  248. end
  249. delete(StatusWaitbar)
  250. end
  251. handles = UpdateStatusSettings(handles);
  252. % Save handles:
  253. set(handles.TextboxDataID, 'String', handles.name.DataID);
  254. guidata(hObject, handles);
  255. % Remove ErrorLog if empty:
  256. if exist([pwd,'/ErrorLog_TrialCleaner.txt'], 'file')
  257. LogCheck = dir('ErrorLog_TrialCleaner.txt');
  258. if LogCheck.bytes == 0
  259. delete('ErrorLog_TrialCleaner.txt')
  260. end
  261. end
  262. %--- Executes on button press in ButtonRedetectInputIDs. --%
  263. %----------------------------------------------------------%
  264. function ButtonRedetectInputIDs_Callback(hObject, eventdata, handles)
  265. % Reset settings & GUI panels:
  266. handles = ResetGroupIDSettings (handles);
  267. handles = ResetSubjIDSettings (handles);
  268. handles = ResetCondIDSettings (handles);
  269. handles = ResetStatusSettings (handles);
  270. handles.paths.InputPreprocMEG = [];
  271. handles.paths.BackupOrigFile = [];
  272. % Compile Group, Subj, and CondIDs for DataID:
  273. % Note: Also initializes Group, Subj, CondIDs.
  274. handles = DetectGroupSubjCond(handles);
  275. if isempty(handles.name.GroupID)
  276. msgbox('ERROR: No GroupID folders detected for selected DataID.')
  277. return;
  278. end
  279. % Compile paths & initialize other variables:
  280. for g = 1:length(handles.name.GroupID)
  281. for s = 1:length(handles.name.SubjID{g})
  282. for c = 1:length(handles.name.CondID)
  283. handles = CompilePaths(handles, g, s, c);
  284. try
  285. handles.gui.InpOutStatus{g}{s,c};
  286. catch
  287. handles.gui.InpOutStatus{g}{s,c} = [];
  288. end
  289. end
  290. end
  291. end
  292. % Update settings & GUI panels:
  293. handles = UpdateGroupIDSettings (handles);
  294. handles = UpdateSubjIDSettings (handles);
  295. handles = UpdateCondIDSettings (handles);
  296. % Detect & update status:
  297. for g = 1:length(handles.name.GroupID)
  298. StatusWaitbar = waitbar(0, ['Please wait. Scanning status for: ', ...
  299. handles.name.GroupID{g}], 'Windowstyle', 'modal');
  300. for s = 1:length(handles.name.SubjID{g})
  301. waitbar(s/length(handles.name.SubjID{g}), StatusWaitbar);
  302. for c = 1:length(handles.name.CondID)
  303. handles = DetectStatus(handles, g, s, c);
  304. end
  305. end
  306. delete(StatusWaitbar)
  307. end
  308. handles = UpdateStatusSettings(handles);
  309. % Save handles:
  310. guidata(hObject, handles);
  311. % Remove ErrorLog if empty:
  312. if exist([pwd,'/ErrorLog_TrialCleaner.txt'], 'file')
  313. LogCheck = dir('ErrorLog_TrialCleaner.txt');
  314. if LogCheck.bytes == 0
  315. delete('ErrorLog_TrialCleaner.txt')
  316. end
  317. end
  318. %--- Detect Group, Subj, and CondID's from DataID: ---%
  319. %-----------------------------------------------------%
  320. function OutputHandles = DetectGroupSubjCond(InputHandles)
  321. handles = InputHandles;
  322. % Reset params:
  323. handles.name.GroupID = [];
  324. handles.name.SubjID = [];
  325. handles.name.CondID = [];
  326. handles.paths.InputPreprocMEG = [];
  327. handles.paths.BackupOrigFile = [];
  328. % Acquire GroupID folders within DataID:
  329. DetectedGroups = dir([handles.paths.DataID,'/GroupID_*']);
  330. RemoveIndex = [];
  331. for g = 1:length(DetectedGroups)
  332. DetectedGroups(g).name(1:8) = []; % Remove "GroupID_" prefix
  333. if DetectedGroups(g).isdir ~= 1
  334. RemoveIndex = [RemoveIndex, g]; % Get unwanted indices
  335. end
  336. end
  337. DetectedGroups(RemoveIndex) = [];
  338. if isempty(DetectedGroups)
  339. handles.name.GroupID = [];
  340. else
  341. handles.name.GroupID = {DetectedGroups.name};
  342. end
  343. % Scan PreprocInput .mat files for SubjID's and CondID's:
  344. CondIDs = [];
  345. for g = 1:length(handles.name.GroupID)
  346. GroupPath = [handles.paths.DataID,'/GroupID_',handles.name.GroupID{g}];
  347. InputMats = dir([GroupPath,'/PreprocInputMEG_*.mat']); % Find InputMats for group
  348. InputMats = {InputMats.name};
  349. SubjIDs = [];
  350. if ~isempty(InputMats)
  351. for m = 1:length(InputMats)
  352. LoadMat = load([GroupPath,'/',InputMats{m}]);
  353. SubjIDs = [SubjIDs; LoadMat.name.SubjID];
  354. CondIDs = [CondIDs; cellstr(LoadMat.name.CurrentCondID)];
  355. end
  356. else
  357. message = {['ERROR: PreprocInputMEG .mat file(s) missing for GroupID: ',...
  358. handles.name.GroupID{g}]; ''; ['As a result, some Subject & Condition IDs ' ...
  359. 'for the selected DataID may not be detected.']};
  360. msgbox(message);
  361. end
  362. handles.name.SubjID{g} = unique(SubjIDs);
  363. end
  364. handles.name.CondID = unique(CondIDs);
  365. % Set output handles:
  366. OutputHandles = handles;
  367. %--- Compiles paths for selected indices: ---%
  368. %--------------------------------------------%
  369. function OutputHandles = CompilePaths(InputHandles, g, s, c)
  370. handles = InputHandles;
  371. handles.paths.InputPreprocMEG{g}{s,c} = ...
  372. [handles.paths.DataID,'/GroupID_',handles.name.GroupID{g},'/', ...
  373. handles.name.CondID{c},'/',handles.name.SubjID{g}{s},'_PreprocMEG.mat'];
  374. handles.paths.BackupOrigFile{g}{s,c} = ...
  375. [handles.paths.DataID,'/GroupID_',handles.name.GroupID{g},'/', ...
  376. handles.name.CondID{c},'/',handles.name.SubjID{g}{s},'_PreprocMEG_OrigBackup.mat'];
  377. % Set output handles:
  378. OutputHandles = handles;
  379. %==========================================%
  380. % FUNCTIONS FOR ADDING OR REMOVING GROUPS: %
  381. %==========================================%
  382. %--- Executes on selection change in ListboxGroupID. ---%
  383. %-------------------------------------------------------%
  384. function ListboxGroupID_Callback(hObject, eventdata, handles)
  385. if isempty(handles.name.GroupID)
  386. return;
  387. end
  388. handles = UpdateSubjIDSettings (handles);
  389. handles = UpdateStatusSettings (handles);
  390. guidata(hObject, handles);
  391. %--- Executes on button press in ButtonRmvGroupID. ---%
  392. %-----------------------------------------------------%
  393. function ButtonRmvGroupID_Callback(hObject, eventdata, handles)
  394. if isempty(handles.name.GroupID)
  395. return;
  396. end
  397. if length(handles.name.GroupID) <= 1
  398. msgbox('Note: Must have at least 1 GroupID.', 'Error:');
  399. return;
  400. end
  401. SelectedIndex = get(handles.ListboxGroupID, 'Value');
  402. handles.name.GroupID(SelectedIndex) = [];
  403. if ~isempty(handles.name.SubjID)
  404. handles.name.SubjID(SelectedIndex) = [];
  405. end
  406. if ~isempty(handles.paths.InputPreprocMEG)
  407. handles.paths.InputPreprocMEG (SelectedIndex) = [];
  408. handles.paths.BackupOrigFile (SelectedIndex) = [];
  409. end
  410. if ~isempty(handles.gui.InpOutStatus)
  411. handles.gui.InpOutStatus(SelectedIndex) = [];
  412. end
  413. % Update settings & GUI:
  414. handles = UpdateGroupIDSettings (handles);
  415. handles = UpdateSubjIDSettings (handles);
  416. handles = UpdateStatusSettings (handles);
  417. % Save handles:
  418. guidata(hObject, handles);
  419. %--- Update GroupID settings & GUI panel: ---%
  420. %--------------------------------------------%
  421. function OutputHandles = UpdateGroupIDSettings(InputHandles)
  422. handles = InputHandles;
  423. % Update listbox:
  424. set(handles.ListboxGroupID, 'String', handles.name.GroupID);
  425. CurrentIndex = get(handles.ListboxGroupID, 'Value');
  426. MaxGroupIndex = length(handles.name.GroupID);
  427. if isempty(CurrentIndex) || CurrentIndex == 0 || CurrentIndex > MaxGroupIndex
  428. set(handles.ListboxGroupID, 'Value', MaxGroupIndex);
  429. end
  430. % Set output handles:
  431. OutputHandles = handles;
  432. %--- Reset GroupID settings & GUI panel: ---%
  433. %-------------------------------------------%
  434. function OutputHandles = ResetGroupIDSettings(InputHandles)
  435. handles = InputHandles;
  436. handles.name.GroupID = [];
  437. set(handles.ListboxGroupID, 'String', []);
  438. set(handles.ListboxGroupID, 'Value', 1);
  439. % Set output handles:
  440. OutputHandles = handles;
  441. %============================================%
  442. % FUNCTIONS FOR ADDING OR REMOVING SUBJECTS: %
  443. %============================================%
  444. %--- Executes on selection change in ListboxSubjID. ---%
  445. %------------------------------------------------------%
  446. function ListboxSubjID_Callback(hObject, eventdata, handles)
  447. if isempty(handles.name.SubjID)
  448. return;
  449. end
  450. GroupIndex = get(handles.ListboxGroupID, 'Value');
  451. if isempty(handles.name.SubjID{GroupIndex})
  452. return;
  453. end
  454. SubjIndex = get(handles.ListboxSubjID, 'Value');
  455. set(handles.ListboxInpOutStatus, 'Value', SubjIndex);
  456. %--- User enters subject to add into this textbox. ---%
  457. %-----------------------------------------------------%
  458. function TextboxSubjID_Callback(hObject, eventdata, handles)
  459. keypress = get(gcf,'CurrentCharacter');
  460. if isequal(keypress, char(13))
  461. ButtonAddSubjID_Callback(hObject, eventdata, handles);
  462. end
  463. %--- Executes on button press in ButtonAddSubjID. ---%
  464. %----------------------------------------------------%
  465. function ButtonAddSubjID_Callback(hObject, eventdata, handles)
  466. if isempty(handles.name.DataID)
  467. msgbox('Warning: Load DataID first.', 'Warning:');
  468. return;
  469. end
  470. if isempty(handles.name.GroupID)
  471. msgbox('Error: No GroupIDs specified.', 'Error:');
  472. return;
  473. end
  474. % Read entered SubjID:
  475. InputSubjID = get(handles.TextboxSubjID, 'String');
  476. InputSubjID = deblank(InputSubjID);
  477. InputSubjID = regexprep(InputSubjID, '\s+', '_');
  478. InputSubjID = cellstr(InputSubjID);
  479. if isempty(InputSubjID{1})
  480. return;
  481. end
  482. GroupIndex = get(handles.ListboxGroupID, 'Value');
  483. if ismember(InputSubjID{1}, handles.name.SubjID{GroupIndex})
  484. return; % If SubjID already added
  485. end
  486. % Add SubjID for group & initialize:
  487. handles.name.SubjID{GroupIndex} = [handles.name.SubjID{GroupIndex}; InputSubjID];
  488. NewSubjIndex = length(handles.name.SubjID{GroupIndex});
  489. for c = 1:length(handles.name.CondID)
  490. handles = CompilePaths(handles, GroupIndex, NewSubjIndex, c);
  491. handles = DetectStatus(handles, GroupIndex, NewSubjIndex, c);
  492. end
  493. % Update settings & GUI:
  494. handles = UpdateSubjIDSettings (handles);
  495. handles = UpdateStatusSettings (handles);
  496. % Save handles:
  497. set(handles.ListboxSubjID, 'Value', NewSubjIndex);
  498. if ~isempty(handles.gui.InpOutStatus)
  499. set(handles.ListboxInpOutStatus, 'Value', NewSubjIndex);
  500. end
  501. guidata(hObject, handles);
  502. %--- Executes on button press in ButtonRmvSubjID. ---%
  503. %----------------------------------------------------%
  504. function ButtonRmvSubjID_Callback(hObject, eventdata, handles)
  505. if isempty(handles.name.SubjID)
  506. return;
  507. end
  508. GroupIndex = get(handles.ListboxGroupID, 'Value');
  509. SubjIndex = get(handles.ListboxSubjID, 'Value');
  510. if isempty(handles.name.SubjID{GroupIndex})
  511. return;
  512. end
  513. handles.name.SubjID{GroupIndex}(SubjIndex) = [];
  514. if ~isempty(handles.paths.InputPreprocMEG)
  515. handles.paths.InputPreprocMEG {GroupIndex}(SubjIndex,:) = [];
  516. handles.paths.BackupOrigFile {GroupIndex}(SubjIndex,:) = [];
  517. end
  518. if ~isempty(handles.gui.InpOutStatus)
  519. handles.gui.InpOutStatus{GroupIndex}(SubjIndex,:) = [];
  520. end
  521. % Update settings & GUI:
  522. handles = UpdateSubjIDSettings (handles);
  523. handles = UpdateStatusSettings (handles);
  524. % Save handles:
  525. guidata(hObject, handles);
  526. %--- Update SubjID settings & GUI panel: ---%
  527. %-------------------------------------------%
  528. function OutputHandles = UpdateSubjIDSettings(InputHandles)
  529. handles = InputHandles;
  530. % Update listbox:
  531. GroupIndex = get(handles.ListboxGroupID, 'Value');
  532. if isempty(handles.name.SubjID)
  533. set(handles.ListboxSubjID, 'String', []);
  534. MaxSubjIndex = 0;
  535. else
  536. set(handles.ListboxSubjID, 'String', handles.name.SubjID{GroupIndex});
  537. MaxSubjIndex = length(handles.name.SubjID{GroupIndex});
  538. end
  539. SubjIndex = get(handles.ListboxSubjID, 'Value');
  540. if isempty(SubjIndex) || SubjIndex == 0 || SubjIndex > MaxSubjIndex
  541. set(handles.ListboxSubjID, 'Value', MaxSubjIndex);
  542. if ~isempty(handles.gui.InpOutStatus)
  543. set(handles.ListboxInpOutStatus, 'Value', MaxSubjIndex);
  544. end
  545. end
  546. % Set output handles:
  547. OutputHandles = handles;
  548. %--- Reset SubjID settings & GUI panel: ---%
  549. %------------------------------------------%
  550. function OutputHandles = ResetSubjIDSettings(InputHandles)
  551. handles = InputHandles;
  552. handles.name.SubjID = [];
  553. set(handles.ListboxSubjID, 'String', []);
  554. set(handles.ListboxSubjID, 'Value', 1);
  555. % Set output handles:
  556. OutputHandles = handles;
  557. %==============================================%
  558. % FUNCTIONS FOR ADDING OR REMOVING CONDITIONS: %
  559. %==============================================%
  560. %--- Executes on selection change in ListboxCondID. ---%
  561. %------------------------------------------------------%
  562. function ListboxCondID_Callback(hObject, eventdata, handles)
  563. if isempty(handles.name.CondID)
  564. return;
  565. end
  566. handles = UpdateStatusSettings(handles);
  567. guidata(hObject, handles);
  568. %--- User enters condition to add into this textbox. ---%
  569. %-------------------------------------------------------%
  570. function TextboxCondID_Callback(hObject, eventdata, handles)
  571. keypress = get(gcf,'CurrentCharacter');
  572. if isequal(keypress, char(13))
  573. ButtonAddCondID_Callback(hObject, eventdata, handles);
  574. end
  575. %--- Executes on button press in ButtonAddCondID. ---%
  576. %----------------------------------------------------%
  577. function ButtonAddCondID_Callback(hObject, eventdata, handles)
  578. if isempty(handles.name.DataID)
  579. msgbox('Warning: Load DataID first.', 'Warning:');
  580. return;
  581. end
  582. if isempty(handles.name.GroupID)
  583. msgbox('Error: No GroupIDs specified.', 'Error:');
  584. return;
  585. end
  586. % Read entered CondID:
  587. InputCondID = get(handles.TextboxCondID, 'String');
  588. InputCondID = deblank(InputCondID);
  589. InputCondID = regexprep(InputCondID, '\s+', '_');
  590. InputCondID = cellstr(InputCondID);
  591. if isempty(InputCondID{1})
  592. return;
  593. end
  594. if ismember(InputCondID{1}, handles.name.CondID)
  595. return; % If CondID already added
  596. end
  597. % Add CondID and initialize:
  598. handles.name.CondID = [handles.name.CondID; InputCondID];
  599. NewCondIndex = length(handles.name.CondID);
  600. for g = 1:length(handles.name.GroupID)
  601. if isempty(handles.name.SubjID)
  602. continue;
  603. end
  604. for s = 1:length(handles.name.SubjID{g})
  605. handles = CompilePaths(handles, g, s, NewCondIndex);
  606. handles = DetectStatus(handles, g, s, NewCondIndex);
  607. end
  608. end
  609. set(handles.ListboxCondID, 'Value', NewCondIndex);
  610. % Update settings & GUI:
  611. handles = UpdateCondIDSettings (handles);
  612. handles = UpdateStatusSettings (handles);
  613. % Save handles:
  614. guidata(hObject, handles);
  615. %--- Executes on button press in ButtonRmvCondID. ---%
  616. %----------------------------------------------------%
  617. function ButtonRmvCondID_Callback(hObject, eventdata, handles)
  618. if isempty(handles.name.CondID)
  619. return;
  620. end
  621. SelectedIndex = get(handles.ListboxCondID, 'Value');
  622. handles.name.CondID(SelectedIndex) = [];
  623. for g = 1:length(handles.name.GroupID)
  624. if ~isempty(handles.paths.InputPreprocMEG)
  625. handles.paths.InputPreprocMEG {g}(:,SelectedIndex) = [];
  626. handles.paths.BackupOrigFile {g}(:,SelectedIndex) = [];
  627. end
  628. if ~isempty(handles.gui.InpOutStatus)
  629. handles.gui.InpOutStatus{g}(:,SelectedIndex) = [];
  630. end
  631. end
  632. % Update settings & GUI:
  633. handles = UpdateCondIDSettings (handles);
  634. handles = UpdateStatusSettings (handles);
  635. % Save handles:
  636. guidata(hObject, handles);
  637. %--- Updates CondID settings & GUI panel: ---%
  638. %--------------------------------------------%
  639. function OutputHandles = UpdateCondIDSettings(InputHandles)
  640. handles = InputHandles;
  641. % Update listbox:
  642. set(handles.ListboxCondID, 'String', handles.name.CondID);
  643. CurrentIndex = get(handles.ListboxCondID, 'Value');
  644. MaxCondIndex = length(handles.name.CondID);
  645. if isempty(CurrentIndex) || CurrentIndex == 0 || CurrentIndex > MaxCondIndex
  646. set(handles.ListboxCondID, 'Value', MaxCondIndex);
  647. end
  648. % Set output handles:
  649. OutputHandles = handles;
  650. %--- Reset CondID settings & GUI panel: ---%
  651. %------------------------------------------%
  652. function OutputHandles = ResetCondIDSettings(InputHandles)
  653. handles = InputHandles;
  654. handles.name.CondID = [];
  655. set(handles.ListboxCondID, 'String', []);
  656. set(handles.ListboxCondID, 'Value', 1);
  657. % Set output handles:
  658. OutputHandles = handles;
  659. %===============================%
  660. % FUNCTIONS FOR STATUS UPDATES: %
  661. %===============================%
  662. %--- Executes on selection change in ListboxInpOutStatus. ---%
  663. %------------------------------------------------------------%
  664. function ListboxInpOutStatus_Callback(hObject, eventdata, handles)
  665. if isempty(handles.gui.InpOutStatus)
  666. return;
  667. end
  668. if ~isempty(handles.name.GroupID) % In case where SubjID exist but CondID missing
  669. GroupIndex = get(handles.ListboxGroupID, 'Value');
  670. if isempty(handles.gui.InpOutStatus{GroupIndex})
  671. return;
  672. end
  673. end
  674. SelectedIndex = get(handles.ListboxInpOutStatus, 'Value');
  675. set(handles.ListboxSubjID, 'Value', SelectedIndex);
  676. %--- Executes on button press in ButtonRefreshStatus. ---%
  677. %--------------------------------------------------------%
  678. function ButtonRefreshStatus_Callback(hObject, eventdata, handles)
  679. % Detect & update status:
  680. for g = 1:length(handles.name.GroupID)
  681. StatusWaitbar = waitbar(0, ['Please wait. Scanning status for: ', ...
  682. handles.name.GroupID{g}], 'Windowstyle', 'modal');
  683. for s = 1:length(handles.name.SubjID{g})
  684. waitbar(s/length(handles.name.SubjID{g}), StatusWaitbar);
  685. for c = 1:length(handles.name.CondID)
  686. handles = DetectStatus(handles, g, s, c);
  687. end
  688. end
  689. delete(StatusWaitbar)
  690. end
  691. handles = UpdateStatusSettings(handles);
  692. % Save handles:
  693. guidata(hObject, handles);
  694. %--- Executes on button press in CheckboxShowRemovedChannels. ---%
  695. %----------------------------------------------------------------%
  696. function CheckboxShowRemovedChannels_Callback(hObject, eventdata, handles)
  697. % Detect & update status:
  698. for g = 1:length(handles.name.GroupID)
  699. StatusWaitbar = waitbar(0, ['Please wait. Scanning status for: ', ...
  700. handles.name.GroupID{g}], 'Windowstyle', 'modal');
  701. for s = 1:length(handles.name.SubjID{g})
  702. waitbar(s/length(handles.name.SubjID{g}), StatusWaitbar);
  703. for c = 1:length(handles.name.CondID)
  704. handles = DetectStatus(handles, g, s, c);
  705. end
  706. end
  707. delete(StatusWaitbar)
  708. end
  709. handles = UpdateStatusSettings(handles);
  710. % Save handles:
  711. guidata(hObject, handles);
  712. %--- Detect input file status: ---%
  713. %---------------------------------%
  714. function OutputHandles = DetectStatus(InputHandles, g, s, c)
  715. handles = InputHandles;
  716. InputPreprocMEG = handles.paths.InputPreprocMEG{g}{s,c};
  717. % Get input or output file status:
  718. if exist(InputPreprocMEG, 'file')
  719. LoadData = LoadFTmat(InputPreprocMEG, 'TrialCleaner');
  720. if isempty(LoadData)
  721. StatusMsg = 'Error: PreprocMEG file found, but contains errors. See ErrorLog.';
  722. elseif ~isfield(LoadData, 'NumTrialsRemoved') && ~isfield(LoadData, 'ChannelsRemoved')
  723. StatusMsg = 'PreprocMEG file found. Ready for cleaning.';
  724. elseif get(handles.CheckboxShowRemovedChannels, 'Value') == 1
  725. if isfield(LoadData, 'ChannelsRemoved')
  726. BadChanStr = [];
  727. for BadChan = 1:length(LoadData.ChannelsRemoved)
  728. if BadChan == 1
  729. BadChanStr = LoadData.ChannelsRemoved{BadChan};
  730. else
  731. BadChanStr = [BadChanStr,', ',LoadData.ChannelsRemoved{BadChan}];
  732. end
  733. end
  734. StatusMsg = ['Channels removed: ',BadChanStr];
  735. else
  736. StatusMsg = 'No channels removed.';
  737. end
  738. else
  739. if isfield(LoadData, 'NumTrialsRemoved')
  740. NumBadTrls = num2str(LoadData.NumTrialsRemoved);
  741. else
  742. NumBadTrls = '0';
  743. end
  744. if isfield(LoadData, 'ChannelsRemoved')
  745. NumBadChls = num2str(length(LoadData.ChannelsRemoved));
  746. else
  747. NumBadChls = '0';
  748. end
  749. StatusMsg = ['Trials removed: ',NumBadTrls,'. Channels removed: ',NumBadChls,'.'];
  750. end
  751. else
  752. StatusMsg = 'Error: PreprocMEG file could not be found.';
  753. end
  754. handles.gui.InpOutStatus{g}{s,c} = StatusMsg;
  755. % Set output handles:
  756. OutputHandles = handles;
  757. %--- Update status settings & GUI panel: ---%
  758. %-------------------------------------------%
  759. function OutputHandles = UpdateStatusSettings(InputHandles)
  760. handles = InputHandles;
  761. % Make sure cells initialized:
  762. for g = 1:length(handles.name.GroupID)
  763. for s = 1:length(handles.name.SubjID{g})
  764. for c = 1:length(handles.name.CondID)
  765. try
  766. handles.gui.InpOutStatus{g}{s,c}; % Check just in case.
  767. catch
  768. handles.gui.InpOutStatus{g}{s,c} = [];
  769. end
  770. end
  771. end
  772. end
  773. % Update listbox:
  774. GroupIndex = get(handles.ListboxGroupID, 'Value');
  775. SubjIndex = get(handles.ListboxSubjID, 'Value');
  776. CondIndex = get(handles.ListboxCondID, 'Value');
  777. if isempty(handles.gui.InpOutStatus) || isempty(handles.gui.InpOutStatus{GroupIndex})
  778. set(handles.ListboxInpOutStatus, 'String', []);
  779. set(handles.ListboxInpOutStatus, 'Value', 1);
  780. else
  781. set(handles.ListboxInpOutStatus, 'String', ...
  782. handles.gui.InpOutStatus{GroupIndex}(:,CondIndex));
  783. if get(handles.ListboxInpOutStatus, 'Value') ~= SubjIndex
  784. set(handles.ListboxInpOutStatus, 'Value', SubjIndex);
  785. end
  786. end
  787. % Set output handles:
  788. OutputHandles = handles;
  789. %--- Reset status settings & GUI panel: ---%
  790. %------------------------------------------%
  791. function OutputHandles = ResetStatusSettings(InputHandles)
  792. handles = InputHandles;
  793. % Reset:
  794. handles.gui.InpOutStatus = [];
  795. % Reinitialize:
  796. for g = 1:length(handles.name.GroupID)
  797. for s = 1:length(handles.name.SubjID{g})
  798. for c = 1:length(handles.name.CondID)
  799. handles.gui.InpOutStatus{g}{s,c} = [];
  800. end
  801. end
  802. end
  803. % Reset GUI listboxes:
  804. set(handles.ListboxInpOutStatus, 'String', []);
  805. set(handles.ListboxInpOutStatus, 'Value', 1);
  806. % Set output handles:
  807. OutputHandles = handles;
  808. %==========================================%
  809. % FUNCTIONS TO MARK BAD TRIALS & CHANNELS: %
  810. %==========================================%
  811. %--- Executes on button press in ButtonShowInstructions. ---%
  812. %-----------------------------------------------------------%
  813. function ButtonShowInstructions_Callback(hObject, eventdata, handles)
  814. Instructions = {'-------------'; 'INSTRUCTIONS:'; '-------------'; '';
  815. 'LOADING INPUT DATA:';
  816. ' 1) Load the DataID that you wish to apply ICA cleaning to.';
  817. ' 2) The DataID will be scanned for Group, Subject & Condition IDs.';
  818. ' 3) Use the "-" keys to exclude datasets from the ICA analysis.';
  819. ' 4) Use the "+" keys to add missing Subject or Condition IDs.';
  820. '';
  821. ' NOTE: To restore the full list of Group, Subject, and Condition IDs';
  822. ' found within the DataID, push the "Redetect Input" button.';
  823. ''; '';
  824. 'REMOVE BAD CHANNEL & TRIALS:';
  825. ' 1) Change viewer settings as needed using the "Viewer Settings" button.';
  826. ' 2) Select the Group, Subj & CondID of the dataset you wish to clean.';
  827. ' 3) Push the "Mark Channels" button to view & mark bad channels.';
  828. ' Push the "Mark Trials" button to view & mark bad trials.'; '';
  829. ' Note: Once you quit the "RejectVisual" viewer, trials/channels marked';
  830. ' as bad will automatically be removed from the dataset.';
  831. ''; '';
  832. 'BACKUP FILES & RESTORATION:';
  833. ' - Before trials and/or channels are removed from a dataset, a BACKUP of';
  834. ' the original dataset is automatically created.'; '';
  835. ' - To UNDO the trial or channel removal for a specific dataset:';
  836. ' 1) Select the Group, Subj & CondID of the dataset to restore.';
  837. ' 2) Push the "Restore Dataset" button.'; ''; ''};
  838. msgbox(Instructions, 'INSTRUCTIONS:')
  839. %--- Executes on button press in ButtonAdvSettings. ---%
  840. %------------------------------------------------------%
  841. function ButtonAdvSettings_Callback(hObject, eventdata, handles)
  842. if isempty(handles.paths.Rootpath)
  843. msgbox('Warning: Select target directory first.', 'Warning:');
  844. return;
  845. end
  846. if isempty(handles.name.DataID)
  847. msgbox('Warning: Load DataID first.', 'Warning:');
  848. return;
  849. end
  850. open([handles.paths.DataID,'/SETTINGS/Settings_RejectVisual.m']);
  851. %--- Executes on button press in ButtonRemoveChannels. ---%
  852. %---------------------------------------------------------%
  853. function ButtonRemoveChannels_Callback(hObject, eventdata, handles)
  854. if isempty(handles.name.DataID)
  855. msgbox('Warning: Load DataID first.', 'Warning:');
  856. return;
  857. end
  858. if isempty(handles.name.GroupID)
  859. msgbox('Error: No GroupIDs specified.', 'Error:');
  860. return;
  861. end
  862. g = get(handles.ListboxGroupID, 'Value');
  863. s = get(handles.ListboxSubjID, 'Value');
  864. c = get(handles.ListboxCondID, 'Value');
  865. if isempty(handles.name.SubjID) || isempty(handles.name.SubjID{g})
  866. msgbox('Error: No SubjIDs specified.', 'Error:');
  867. return;
  868. end
  869. if isempty(handles.name.CondID)
  870. msgbox('Error: No CondIDs specified.', 'Error:');
  871. return;
  872. end
  873. % Call viewer for user to mark bad channels:
  874. RmvBadChannelsTrials(handles, g, s, c, 'channel')
  875. % Detect & update status:
  876. handles = DetectStatus(handles, g, s, c);
  877. handles = UpdateStatusSettings(handles);
  878. % Save handles:
  879. guidata(hObject, handles);
  880. % Remove ErrorLog if empty:
  881. if exist([pwd,'/ErrorLog_TrialCleaner.txt'], 'file')
  882. LogCheck = dir('ErrorLog_TrialCleaner.txt');
  883. if LogCheck.bytes == 0
  884. delete('ErrorLog_TrialCleaner.txt')
  885. end
  886. end
  887. %--- Executes on button press in ButtonRemoveTrials. ---%
  888. %-------------------------------------------------------%
  889. function ButtonRemoveTrials_Callback(hObject, eventdata, handles)
  890. if isempty(handles.name.DataID)
  891. msgbox('Warning: Load DataID first.', 'Warning:');
  892. return;
  893. end
  894. if isempty(handles.name.GroupID)
  895. msgbox('Error: No GroupIDs specified.', 'Error:');
  896. return;
  897. end
  898. g = get(handles.ListboxGroupID, 'Value');
  899. s = get(handles.ListboxSubjID, 'Value');
  900. c = get(handles.ListboxCondID, 'Value');
  901. if isempty(handles.name.SubjID) || isempty(handles.name.SubjID{g})
  902. msgbox('Error: No SubjIDs specified.', 'Error:');
  903. return;
  904. end
  905. if isempty(handles.name.CondID)
  906. msgbox('Error: No CondIDs specified.', 'Error:');
  907. return;
  908. end
  909. % Call viewer for user to mark bad channels:
  910. RmvBadChannelsTrials(handles, g, s, c, 'trial')
  911. % Detect & update status:
  912. handles = DetectStatus(handles, g, s, c);
  913. handles = UpdateStatusSettings(handles);
  914. % Save handles:
  915. guidata(hObject, handles);
  916. % Remove ErrorLog if empty:
  917. if exist([pwd,'/ErrorLog_TrialCleaner.txt'], 'file')
  918. LogCheck = dir('ErrorLog_TrialCleaner.txt');
  919. if LogCheck.bytes == 0
  920. delete('ErrorLog_TrialCleaner.txt')
  921. end
  922. end
  923. %--- Calls viewer and housekeeping for channel & trial removal: ---%
  924. %------------------------------------------------------------------%
  925. function RmvBadChannelsTrials(InputHandles, g, s, c, RmvMode)
  926. handles = InputHandles;
  927. InputPreprocMEG = handles.paths.InputPreprocMEG{g}{s,c};
  928. BackupOrigFile = handles.paths.BackupOrigFile{g}{s,c};
  929. % Load input data & parameters:
  930. MEGdata = LoadFTmat(InputPreprocMEG, 'TrialCleaner');
  931. if isempty(MEGdata)
  932. msgbox('Error: Input PreprocMEG file contains errors. See ErrorLog.')
  933. return;
  934. end
  935. CurrentDir = pwd;
  936. cd([handles.paths.DataID,'/SETTINGS/']);
  937. cfgReject = Settings_RejectVisual;
  938. cd(CurrentDir);
  939. cfgReject.method = RmvMode; % Viewing by 'channel' or 'trial'
  940. % Log extra [MEG]PLS fields (ft_rejectvisual will remove them by default):
  941. Backup = [];
  942. if isfield(MEGdata, 'AllEventInfo')
  943. Backup.AllEventInfo = MEGdata.AllEventInfo;
  944. end
  945. if isfield(MEGdata, 'ICAcompRemoved')
  946. Backup.ICAcompRemoved = MEGdata.ICAcompRemoved;
  947. end
  948. if isfield(MEGdata, 'ChannelsRemoved')
  949. Backup.ChannelsRemoved = MEGdata.ChannelsRemoved;
  950. end
  951. if isfield(MEGdata, 'NumTrialsRemoved')
  952. Backup.NumTrialsRemoved = MEGdata.NumTrialsRemoved;
  953. end
  954. % Make sure only relevant channels are shown in the viewer:
  955. % By default, all channels are shown and unselected channels are marked as bad.
  956. if strcmp(cfgReject.keepchannel, 'no')
  957. cfgSelect = [];
  958. cfgSelect.channel = cfgReject.channel;
  959. MEGdata = ft_selectdata_new(cfgSelect, MEGdata);
  960. end
  961. % Run "ft_rejectvisual":
  962. OrigChanList = MEGdata.label; % Log original channel list
  963. MEGdata = ft_rejectvisual(cfgReject, MEGdata)
  964. % Place extra [MEG]PLS fields back in:
  965. if isfield(Backup, 'AllEventInfo')
  966. MEGdata.AllEventInfo = Backup.AllEventInfo;
  967. end
  968. if isfield(Backup, 'ICAcompRemoved')
  969. MEGdata.ICAcompRemoved = Backup.ICAcompRemoved;
  970. end
  971. if isfield(Backup, 'ChannelsRemoved')
  972. MEGdata.ChannelsRemoved = Backup.ChannelsRemoved;
  973. end
  974. if isfield(Backup, 'NumTrialsRemoved')
  975. MEGdata.NumTrialsRemoved = Backup.NumTrialsRemoved;
  976. end
  977. % Detect & log removed channels & trials:
  978. if ~isequal(MEGdata.label, OrigChanList)
  979. BadChannels = OrigChanList(~ismember(OrigChanList, MEGdata.label));
  980. if isfield(MEGdata, 'ChannelsRemoved')
  981. MEGdata.ChannelsRemoved = [MEGdata.ChannelsRemoved; BadChannels];
  982. else
  983. MEGdata.ChannelsRemoved = BadChannels;
  984. end
  985. end
  986. if ~isempty(MEGdata.cfg.artifact)
  987. NumBadTrls = size(MEGdata.cfg.artifact, 1);
  988. if isfield(MEGdata, 'NumTrialsRemoved')
  989. MEGdata.NumTrialsRemoved = MEGdata.NumTrialsRemoved + NumBadTrls;
  990. else
  991. MEGdata.NumTrialsRemoved = NumBadTrls;
  992. end
  993. end
  994. % If channels / trials were removed, create backup & save:
  995. if isfield(MEGdata, 'ChannelsRemoved') || isfield(MEGdata, 'NumTrialsRemoved')
  996. if ~exist(BackupOrigFile, 'file')
  997. success = copyfile(InputPreprocMEG, BackupOrigFile, 'f');
  998. if success == 0
  999. msgbox('Warning: Failed to create backup of original file.', 'Warning:')
  1000. end
  1001. end
  1002. CheckSavePath(InputPreprocMEG, 'TrialCleaner');
  1003. save(InputPreprocMEG, 'MEGdata');
  1004. end
  1005. %--- Executes on button press in ButtonRestoreDataset. ---%
  1006. %---------------------------------------------------------%
  1007. function ButtonRestoreDataset_Callback(hObject, eventdata, handles)
  1008. if isempty(handles.name.DataID)
  1009. msgbox('Warning: Load DataID first.', 'Warning:');
  1010. return;
  1011. end
  1012. if isempty(handles.name.GroupID)
  1013. msgbox('Error: No GroupIDs specified.', 'Error:');
  1014. return;
  1015. end
  1016. g = get(handles.ListboxGroupID, 'Value');
  1017. s = get(handles.ListboxSubjID, 'Value');
  1018. c = get(handles.ListboxCondID, 'Value');
  1019. if isempty(handles.name.SubjID) || isempty(handles.name.SubjID{g})
  1020. msgbox('Error: No SubjIDs specified.', 'Error:');
  1021. return;
  1022. end
  1023. if isempty(handles.name.CondID)
  1024. msgbox('Error: No CondIDs specified.', 'Error:');
  1025. return;
  1026. end
  1027. % Check for backup file:
  1028. InputPreprocMEG = handles.paths.InputPreprocMEG{g}{s,c};
  1029. BackupOrigFile = handles.paths.BackupOrigFile{g}{s,c};
  1030. if ~exist(BackupOrigFile, 'file')
  1031. msgbox('Error: Backup PreprocMEG file could not be found.', 'Error:')
  1032. return;
  1033. end
  1034. % Confirm restoration:
  1035. prompt = {'WARNING:'; '';
  1036. 'Do you wish to RESTORE this dataset to its ORIGINAL state?';
  1037. 'This will undo any channel or trial removal previously done.'; ''};
  1038. Restore = questdlg(prompt, 'WARNING:', 'YES', 'NO', 'NO');
  1039. if strcmp(Restore, 'NO')
  1040. return;
  1041. end
  1042. % Restore backup:
  1043. if exist(BackupOrigFile, 'file')
  1044. CheckSavePath(InputPreprocMEG, 'TrialCleaner');
  1045. success = movefile(BackupOrigFile, InputPreprocMEG, 'f');
  1046. if success == 0
  1047. msgbox('Error: Failed to restore to original PreprocMEG file.', 'Error:')
  1048. end
  1049. end
  1050. % Detect & update status:
  1051. handles = DetectStatus(handles, g, s, c);
  1052. handles = UpdateStatusSettings(handles);
  1053. % Save handles:
  1054. guidata(hObject, handles);
  1055. %--- Executes on button press in ButtonRestoreAll. ---%
  1056. %-----------------------------------------------------%
  1057. function ButtonRestoreAll_Callback(hObject, eventdata, handles)
  1058. if isempty(handles.name.DataID)
  1059. msgbox('Warning: Load DataID first.', 'Warning:');
  1060. return;
  1061. end
  1062. if isempty(handles.name.GroupID)
  1063. msgbox('Error: No GroupIDs specified.', 'Error:');
  1064. return;
  1065. end
  1066. if isempty(handles.name.SubjID)
  1067. msgbox('Error: No SubjIDs specified.', 'Error:');
  1068. return;
  1069. else
  1070. g = get(handles.ListboxGroupID, 'Value');
  1071. if isempty(handles.name.SubjID{g})
  1072. msgbox('Error: No SubjIDs added for selected Group.', 'Error:')
  1073. return;
  1074. end
  1075. end
  1076. if isempty(handles.name.CondID)
  1077. msgbox('Error: No CondIDs specified.', 'Error:');
  1078. return;
  1079. end
  1080. % Confirm restoration:
  1081. prompt = {'WARNING:'; '';
  1082. 'This will RESTORE ALL current datasets to their BACKUP state.';
  1083. 'Any channel or trial removal previously done will be reverted.';
  1084. 'Do you wish to continue?'; '';
  1085. 'Note: Only datasets with backup file states will be restored.';
  1086. ' If a backup file is not found, the dataset will be skipped.'; ''};
  1087. Restore = questdlg(prompt, 'WARNING:', 'YES', 'NO', 'NO');
  1088. if strcmp(Restore, 'NO')
  1089. return;
  1090. end
  1091. % Restore all datasets to original state:
  1092. for g = 1:length(handles.name.GroupID)
  1093. for s = 1:length(handles.name.SubjID{g})
  1094. for c = 1:length(handles.name.CondID)
  1095. InputPreprocMEG = handles.paths.InputPreprocMEG{g}{s,c};
  1096. BackupOrigFile = handles.paths.BackupOrigFile{g}{s,c};
  1097. if exist(BackupOrigFile, 'file')
  1098. CheckSavePath(InputPreprocMEG, 'TrialCleaner');
  1099. success = movefile(BackupOrigFile, InputPreprocMEG, 'f');
  1100. if success == 1
  1101. StatusMsg = 'Backup PreprocMEG file restored successfully.';
  1102. else
  1103. StatusMsg = 'Error: Failed to restore backup PreprocMEG file.';
  1104. end
  1105. else
  1106. StatusMsg = 'Warning: No backup PreprocMEG file found. Skipped restore.';
  1107. end
  1108. handles.gui.InpOutStatus{g}{s,c} = StatusMsg;
  1109. end % Cond
  1110. end % Subj
  1111. end % Group
  1112. % Update status:
  1113. handles = UpdateStatusSettings(handles);
  1114. % Save handles:
  1115. guidata(hObject, handles);
  1116. %=================================%
  1117. % FUNCTION TO OPEN MODAL WAITBOX: %
  1118. %=================================%
  1119. function WaitBox = StartWaitBox(TextString)
  1120. WaitBox = dialog('Units', 'pixels', 'Position', [500 500 300 40],...
  1121. 'Windowstyle', 'modal', 'NextPlot', 'new', 'Name', 'Please Wait:');
  1122. uicontrol('Parent', WaitBox, 'Units', 'pixels', 'Position', [20 10 250 20],...
  1123. 'Style', 'text', 'String', TextString, 'FontWeight', 'bold');
  1124. movegui(WaitBox, 'center');
  1125. %============================%
  1126. % GUIDE CREATEFCN FUNCTIONS: %
  1127. %============================%
  1128. % --- Executes during object creation, after setting all properties.
  1129. function TextboxRootpath_CreateFcn(hObject, eventdata, handles)
  1130. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1131. set(hObject,'BackgroundColor','white');
  1132. end
  1133. % --- Executes during object creation, after setting all properties.
  1134. function TextboxDataID_CreateFcn(hObject, eventdata, handles)
  1135. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1136. set(hObject,'BackgroundColor','white');
  1137. end
  1138. % --- Executes during object creation, after setting all properties.
  1139. function ListboxGroupID_CreateFcn(hObject, eventdata, handles)
  1140. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1141. set(hObject,'BackgroundColor','white');
  1142. end
  1143. % --- Executes during object creation, after setting all properties.
  1144. function ListboxSubjID_CreateFcn(hObject, eventdata, handles)
  1145. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1146. set(hObject,'BackgroundColor','white');
  1147. end
  1148. % --- Executes during object creation, after setting all properties.
  1149. function TextboxSubjID_CreateFcn(hObject, eventdata, handles)
  1150. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1151. set(hObject,'BackgroundColor','white');
  1152. end
  1153. % --- Executes during object creation, after setting all properties.
  1154. function ListboxCondID_CreateFcn(hObject, eventdata, handles)
  1155. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1156. set(hObject,'BackgroundColor','white');
  1157. end
  1158. % --- Executes during object creation, after setting all properties.
  1159. function TextboxCondID_CreateFcn(hObject, eventdata, handles)
  1160. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1161. set(hObject,'BackgroundColor','white');
  1162. end
  1163. % --- Executes during object creation, after setting all properties.
  1164. function ListboxInpOutStatus_CreateFcn(hObject, eventdata, handles)
  1165. if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
  1166. set(hObject,'BackgroundColor','white');
  1167. end